/*
 * $Id: ReflectUtil.java 9 2006-03-08 10:21:59Z wjx $
 */
package com.someok.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Misc java.lang.reflect utils.
 *
 * <p><a href="ReflectUtil.java.html"><i>View Source</i></a></p>
 *
 * @version $Revision: 9 $ $Date: 2006-03-08 18:21:59 +0800 (星期三, 08 三月 2006) $
 */
public final class ReflectUtil {

	/**
	 * Returns method from an object, matched by name.
	 *
	 * @param o          Object that is examined.
	 * @param methodName Full name of the method.
	 *
	 * @return null if method not found
	 */
	public static Method getMethod(Object o, String methodName) {
		if ((methodName == null) || (o == null)) {
			return null;
		}
		Method[] ms = o.getClass().getMethods();
		for (int i = 0; i < ms.length; i++) {
			Method m = ms[i];
			if (m.getName().equals(methodName)) {
				return m;
			}
		}
		return null;
	}


	/**
	 * Invokes a method in object.
	 *
	 * @param obj    object
	 * @param method name of the objects method
	 * @param params method parameters
	 * @param param_types
	 *               method parameter types
	 *
	 * @return invoked method results
	 * @exception IllegalAccessException
	 * @exception NoSuchMethodException
	 * @exception InvocationTargetException
	 */
	public static Object invoke(Object obj, String method, Object[] params, Class[] param_types) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
		Method m = obj.getClass().getMethod(method, param_types);
		return m.invoke(obj, params);
	}


	/**
	 * Invokes method of an object without specifying parameter types.
	 * It examines all methods of object and finds those that has the same name.
	 * Mathced methods are further examined for types: if given parameters
	 * are instances of matched method types then method is matched and will
	 * be executed.
	 *
	 * @param obj    object
	 * @param method method of an object
	 * @param params method parameters
	 *
	 * @return whatever invoked method returns
	 * @exception IllegalAccessException
	 * @exception NoSuchMethodException
	 * @exception InvocationTargetException
	 */
	public static Object invoke(Object obj, String method, Object[] params) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
		Method[] all_methods = obj.getClass().getMethods();
		Method method2invoke = null;

		// find method with the same name and matching argument types
		for (int i = 0; i < all_methods.length; i++) {
			Method m = all_methods[i];
			if (m.getName().equals(method)) {
				Class[] pt = m.getParameterTypes();
				boolean match = true;
				int match_loops = pt.length;
				if (match_loops != params.length) {
					continue;
				}
				for (int j = 0; j < match_loops; j++) {
					if (pt[i].isInstance(params[i]) == false) {
						match = false;
						break;
					}
				}
				if (match == true) {
					method2invoke = m;
				}
			}
		}

		// throw an exception if no method to invoke
		if (method2invoke == null) {
			String t = "(";
			for (int i = 0; i < params.length; i++) {
				if (i != 0) {
					t += ", ";
				}
				t += params[i].getClass().getName();
			}
			t += ")";
			throw new NoSuchMethodException(obj.getClass().getName() + "." + method + t);
		}

		// finally, invoke founded method
		return method2invoke.invoke(obj, params);
	}
}
